#include "../include/gudb.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

// Test utility functions
static void test_print(const char* test_name, int success) {
    printf("[%s] %s\n", success ? "PASS" : "FAIL", test_name);
}

static int cleanup_test_dir(const char* dir) {
    char cmd[512];
    snprintf(cmd, sizeof(cmd), "rm -rf %s", dir);
    return system(cmd);
}

// Test basic database operations
static int test_database_lifecycle() {
    printf("\n=== Testing Database Lifecycle ===\n");
    
    const char* test_dir = "./test_db";
    int success = 1;
    
    // Clean up any existing test directory
    cleanup_test_dir(test_dir);
    
    // Test database creation and opening
    gudb* db = gudb_open(test_dir, GU_OPEN_CREATE | GU_OPEN_READWRITE, "admin", "password");
    if (!db) {
        printf("Failed to open database: %s\n", gudb_error(NULL));
        success = 0;
    }
    test_print("Database Open", db != NULL);
    
    if (db) {
        // Test database closing
        int close_result = gudb_close(db);
        test_print("Database Close", close_result == GU_OK);
        
        if (close_result != GU_OK) {
            success = 0;
        }
    }
    
    // Clean up
    cleanup_test_dir(test_dir);
    
    return success;
}

// Test transaction operations
static int test_transactions() {
    printf("\n=== Testing Transactions ===\n");
    
    const char* test_dir = "./test_db_txn";
    int success = 1;
    
    // Clean up any existing test directory
    cleanup_test_dir(test_dir);
    
    // Open database
    gudb* db = gudb_open(test_dir, GU_OPEN_CREATE | GU_OPEN_READWRITE, "admin", "password");
    if (!db) {
        printf("Failed to open database for transaction test\n");
        return 0;
    }
    
    // Test transaction begin
    gudb_txn* txn = gudb_begin(db, GU_TXN_RC);
    test_print("Transaction Begin", txn != NULL);
    
    if (txn) {
        // Test basic SQL execution (currently placeholder)
        result_t* result = NULL;
        int exec_result = gudb_exec(txn, "SELECT 1", NULL, &result);
        test_print("SQL Execution", exec_result == GU_OK);
        
        if (result) {
            gudb_free_result(result);
        }
        
        // Test transaction commit
        int commit_result = gudb_commit(txn);
        test_print("Transaction Commit", commit_result == GU_OK);
        
        if (exec_result != GU_OK || commit_result != GU_OK) {
            success = 0;
        }
    } else {
        success = 0;
    }
    
    // Test transaction rollback
    txn = gudb_begin(db, GU_TXN_RC);
    if (txn) {
        int rollback_result = gudb_rollback(txn);
        test_print("Transaction Rollback", rollback_result == GU_OK);
        
        if (rollback_result != GU_OK) {
            success = 0;
        }
    }
    
    // Close database
    gudb_close(db);
    
    // Clean up
    cleanup_test_dir(test_dir);
    
    return success;
}

// Test file creation and structure
static int test_file_structure() {
    printf("\n=== Testing File Structure ===\n");
    
    const char* test_dir = "./test_db_files";
    int success = 1;
    
    // Clean up any existing test directory
    cleanup_test_dir(test_dir);
    
    // Open database to create files
    gudb* db = gudb_open(test_dir, GU_OPEN_CREATE | GU_OPEN_READWRITE, "admin", "password");
    if (!db) {
        printf("Failed to open database for file structure test\n");
        return 0;
    }
    
    // Close database
    gudb_close(db);
    
    // Check if all required files were created
    char filepath[512];
    const char* required_files[] = {
        "gudb.dat", "gudb.wal", "gudb.binlog", 
        "gudb.meta", "gudb.log", "gudb.lock"
    };
    
    for (int i = 0; i < 6; i++) {
        snprintf(filepath, sizeof(filepath), "%s/%s", test_dir, required_files[i]);
        
        struct stat st;
        int file_exists = (stat(filepath, &st) == 0);
        
        char test_name[128];
        snprintf(test_name, sizeof(test_name), "File Created: %s", required_files[i]);
        test_print(test_name, file_exists);
        
        if (!file_exists) {
            success = 0;
        }
    }
    
    // Clean up
    cleanup_test_dir(test_dir);
    
    return success;
}

// Test error handling
static int test_error_handling() {
    printf("\n=== Testing Error Handling ===\n");
    
    int success = 1;
    
    // Test opening non-existent database without CREATE flag
    gudb* db = gudb_open("./non_existent_db", GU_OPEN_READWRITE, "admin", "password");
    test_print("Non-existent DB Error", db == NULL);
    
    if (db != NULL) {
        gudb_close(db);
        cleanup_test_dir("./non_existent_db");
        success = 0;
    }
    
    // Test NULL parameters
    db = gudb_open(NULL, GU_OPEN_CREATE, "admin", "password");
    test_print("NULL Path Error", db == NULL);
    
    if (db != NULL) {
        gudb_close(db);
        success = 0;
    }
    
    db = gudb_open("./test", GU_OPEN_CREATE, NULL, "password");
    test_print("NULL User Error", db == NULL);
    
    if (db != NULL) {
        gudb_close(db);
        cleanup_test_dir("./test");
        success = 0;
    }
    
    return success;
}

// Test authentication (basic)
static int test_authentication() {
    printf("\n=== Testing Authentication ===\n");
    
    const char* test_dir = "./test_db_auth";
    int success = 1;
    
    // Clean up any existing test directory
    cleanup_test_dir(test_dir);
    
    // Test with default admin user
    gudb* db = gudb_open(test_dir, GU_OPEN_CREATE | GU_OPEN_READWRITE, "admin", "password");
    test_print("Admin Authentication", db != NULL);
    
    if (db) {
        gudb_close(db);
    } else {
        success = 0;
    }
    
    // Test with non-existent user (should fail)
    db = gudb_open(test_dir, GU_OPEN_READWRITE, "nonexistent", "password");
    test_print("Invalid User Rejection", db == NULL);
    
    if (db != NULL) {
        gudb_close(db);
        success = 0;
    }
    
    // Clean up
    cleanup_test_dir(test_dir);
    
    return success;
}

// Main test runner
int main() {
    printf("GuDB Basic Framework Tests\n");
    printf("==========================\n");
    
    int total_tests = 0;
    int passed_tests = 0;
    
    // Run all test suites
    struct {
        const char* name;
        int (*test_func)(void);
    } test_suites[] = {
        {"Database Lifecycle", test_database_lifecycle},
        {"Transactions", test_transactions},
        {"File Structure", test_file_structure},
        {"Error Handling", test_error_handling},
        {"Authentication", test_authentication}
    };
    
    int num_suites = sizeof(test_suites) / sizeof(test_suites[0]);
    
    for (int i = 0; i < num_suites; i++) {
        printf("\nRunning test suite: %s\n", test_suites[i].name);
        
        int suite_result = test_suites[i].test_func();
        total_tests++;
        
        if (suite_result) {
            passed_tests++;
            printf("Suite PASSED: %s\n", test_suites[i].name);
        } else {
            printf("Suite FAILED: %s\n", test_suites[i].name);
        }
    }
    
    // Print summary
    printf("\n========================================\n");
    printf("Test Results: %d/%d suites passed\n", passed_tests, total_tests);
    
    if (passed_tests == total_tests) {
        printf("All tests PASSED!\n");
        return 0;
    } else {
        printf("Some tests FAILED!\n");
        return 1;
    }
}